//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//********************************************************* 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using Microsoft.VisualStudio.Tools.Office.Runtime.Security;

namespace Microsoft.TridentWordAddIn.Setup.CustomActions
{
    [RunInstaller(true)]
    [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    public partial class CustomActionManager : Installer
    {
        private const string PublicKey = "<RSAKeyValue><Modulus>uzGQcSw8jUZ/Hz3dhvkdhIrHxAL3RK8Ti59O64H5LfrjuBkJ3vCoTRLTiXwauAsZxvmeIlthg+U5zO3CzEKPQV6caCivQf9U5Swj3w8XStTbcFyROO4pEl4PKdkaN9+7p4MZUSwoBUlh34XEnKHN1HirSWSUdKCvJwAik+ZJDZ0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
        private static bool? result = null;
        private List<Process> processList = new List<Process>();
       
        /// <summary>
        /// Initializes a new instance of the <see cref="CustomActionManager"/> class.
        /// </summary>
        public CustomActionManager()
        {                    
            InitializeComponent();            
        }

        /// <summary>
        /// When overridden in a derived class, performs the installation.
        /// </summary>
        /// <param name="stateSaver">An <see cref="T:System.Collections.IDictionary"/> used to save information needed to perform a commit, rollback, or uninstall operation.</param>
        /// <exception cref="T:System.ArgumentException">The <paramref name="stateSaver"/> parameter is null. </exception>
        /// <exception cref="T:System.Exception">An exception occurred in the <see cref="E:System.Configuration.Install.Installer.BeforeInstall"/> event handler of one of the installers in the collection.-or- An exception occurred in the <see cref="E:System.Configuration.Install.Installer.AfterInstall"/> event handler of one of the installers in the collection. </exception>
        public override void Install(System.Collections.IDictionary stateSaver)
        {
            this.CheckForWindowInstance();
            if (result == false)
            {
                throw new InstallException("Installation could not complete successfully as it has been canceled/aborted.");
            }
            else if (result == null || result == true)
            {
                try
                {
                    string allUsers = this.Context.Parameters["allusers"];
                    string targetDirectory = this.Context.Parameters["targetDir"];
                  
                    base.Install(stateSaver);
                    RegisterOffice2007AddIn.RemoveTridentWordAddInDeleteInstruction();                    
                    RegisterOffice2007AddIn.CreateAppRegistryEntries(allUsers, targetDirectory);                                       
                    if (allUsers != null && allUsers.CompareTo("1") == 0)
                    {
                        RegisterOffice2007AddIn.IncrementCount();
                    }

                    Uri deploymentManifestLocation = new Uri(Path.Combine(targetDirectory, "Microsoft.TridentWordAddIn.AddIn.vsto"));
                    AddInSecurityEntry entry = new AddInSecurityEntry(deploymentManifestLocation, PublicKey);
                    UserInclusionList.Add(entry);
                    stateSaver.Add("entryKey", deploymentManifestLocation);                   
                }
                catch (Exception)
                {
                }
            }
        }

        /// <summary>
        /// When overridden in a derived class, restores the pre-installation state of the computer.
        /// </summary>
        /// <param name="savedState">An <see cref="T:System.Collections.IDictionary"/> that contains the pre-installation state of the computer.</param>
        /// <exception cref="T:System.ArgumentException">The <paramref name="savedState"/> parameter is null.-or- The saved-state <see cref="T:System.Collections.IDictionary"/> might have been corrupted. </exception>
        /// <exception cref="T:System.Configuration.Install.InstallException">An exception occurred during the <see cref="M:System.Configuration.Install.Installer.Rollback(System.Collections.IDictionary)"/> phase of the installation. This exception is ignored and the rollback continues. However, the computer might not be fully reverted to its initial state after the rollback completes. </exception>
        public override void Rollback(System.Collections.IDictionary savedState)
        {
            if (result == null || result == true)
            {
                base.Rollback(savedState);
            }
        }

        /// <summary>
        /// When overridden in a derived class, removes an installation.
        /// </summary>
        /// <param name="savedState">An <see cref="T:System.Collections.IDictionary"/> that contains the state of the computer after the installation was complete.</param>
        /// <exception cref="T:System.ArgumentException">The saved-state <see cref="T:System.Collections.IDictionary"/> might have been corrupted. </exception>
        /// <exception cref="T:System.Configuration.Install.InstallException">An exception occurred while uninstalling. This exception is ignored and the uninstall continues. However, the application might not be fully uninstalled after the uninstallation completes. </exception>
        public override void Uninstall(System.Collections.IDictionary savedState)
        {
            if (result == null)
            {
                try
                {
                    this.DeleteApplicationFiles();
                    RegisterOffice2007AddIn.RemoveAppRegistryEntries();
                    Uri deploymentManifestLocation = (Uri)savedState["entryKey"];
                    if (deploymentManifestLocation != null)
                    {
                        UserInclusionList.Remove(deploymentManifestLocation);
                    }

                    base.Uninstall(savedState);
                }
                catch (Exception) 
                {
                }
            }
        }

        /// <summary>
        /// Checks for window instance.
        /// </summary>
        private void CheckForWindowInstance()
        {
            while (this.IsWinWordRunning())
            {
                using (InstallRetryDialog installationRetryDialog = new InstallRetryDialog())
                {
                    installationRetryDialog.UpdateProcessList(this.processList);
                    DialogResult closeWordResult = installationRetryDialog.ShowDialog();
                    if (closeWordResult == DialogResult.Retry)
                    {
                        result = true;
                    }
                    else
                    {
                        result = false;
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// Determines whether WinWord is running.
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if WinWord is running; otherwise, <c>false</c>.
        /// </returns>
        private bool IsWinWordRunning()
        {
            bool returnState = false;
            this.processList.Clear();

            Process[] processes = Process.GetProcessesByName("WINWORD");
            if (processes != null)
            {
                foreach (Process p in processes)
                {
                    if (!string.IsNullOrEmpty(p.MainWindowTitle))
                    {
                        this.processList.Add(p);
                        returnState = true;
                    }
                }
            }

            return returnState;
        }

        /// <summary>
        /// Deletes the application files.
        /// </summary>
        private void DeleteApplicationFiles()
        {
            const string Folder = @"\TridentWordAddIn";
            string applicationDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + Folder;            
            if (Directory.Exists(applicationDataPath))
            {
                Directory.Delete(applicationDataPath, true);
            }

            string targetDirectory = this.Context.Parameters["targetDir"];
            if (Directory.Exists(targetDirectory))
            {
                Directory.Delete(targetDirectory, true);
            }
        }
    }
}
